<template>
  <div class="flow-designer">
    <div class="designer-header">
      <div class="header-left">
        <el-icon class="back-icon" @click="$router.back()"><ArrowLeft /></el-icon>
        <span class="title">{{ flowData.name || '未命名流程' }}</span>
        <el-tag v-if="!isSaved" type="warning" size="small">未保存</el-tag>
      </div>
      <div class="header-actions">
        <el-button @click="handlePreview">
          <el-icon><View /></el-icon>
          预览
        </el-button>
        <el-button @click="showAIDialog = true" type="primary">
          <el-icon><MagicStick /></el-icon>
          AI助手
        </el-button>
        <el-button type="success" @click="handleSave">
          <el-icon><Select /></el-icon>
          保存
        </el-button>
        <el-button @click="handlePublish">
          <el-icon><Promotion /></el-icon>
          发布
        </el-button>
      </div>
    </div>

    <div class="designer-body">
      <!-- 左侧节点面板 -->
      <div class="node-panel">
        <div class="panel-title">流程节点</div>
        <div class="node-list">
          <div 
            v-for="node in nodeTypes" 
            :key="node.type"
            class="node-item"
            draggable="true"
            @dragstart="handleDragStart(node)"
          >
            <div class="node-icon" :style="{ background: node.color }">
              <el-icon><component :is="node.icon" /></el-icon>
            </div>
            <span class="node-label">{{ node.label }}</span>
          </div>
        </div>

        <el-divider />

        <div class="panel-title">流程信息</div>
        <div class="flow-info">
          <div class="info-item">
            <span class="label">节点数量：</span>
            <span class="value">{{ flowNodes.length }}</span>
          </div>
          <div class="info-item">
            <span class="label">连接数量：</span>
            <span class="value">{{ connections.length }}</span>
          </div>
          <div class="info-item">
            <span class="label">状态：</span>
            <el-tag :type="isValidFlow ? 'success' : 'warning'" size="small">
              {{ isValidFlow ? '有效' : '未完成' }}
            </el-tag>
          </div>
        </div>
      </div>

      <!-- 中间画布区域 -->
      <div class="canvas-panel">
        <div class="canvas-toolbar">
          <el-button-group>
            <el-button @click="handleZoomIn">
              <el-icon><ZoomIn /></el-icon>
            </el-button>
            <el-button @click="handleZoomOut">
              <el-icon><ZoomOut /></el-icon>
            </el-button>
            <el-button @click="handleFitView">
              <el-icon><FullScreen /></el-icon>
              适应画布
            </el-button>
          </el-button-group>

          <div class="zoom-level">{{ Math.round(zoomLevel * 100) }}%</div>

          <div class="canvas-actions">
            <el-button @click="handleClear">
              <el-icon><Delete /></el-icon>
              清空
            </el-button>
            <el-button @click="handleUndo" :disabled="!canUndo">
              <el-icon><RefreshLeft /></el-icon>
              撤销
            </el-button>
            <el-button @click="handleRedo" :disabled="!canRedo">
              <el-icon><RefreshRight /></el-icon>
              重做
            </el-button>
          </div>
        </div>

        <div 
          class="canvas-container"
          ref="canvasRef"
          @drop="handleDrop"
          @dragover.prevent
          @click="deselectAll"
        >
          <div class="canvas-content" :style="canvasStyle">
            <el-empty v-if="flowNodes.length === 0" description="拖拽左侧节点到此处开始设计流程">
              <el-button type="primary" @click="showAIDialog = true">
                <el-icon><MagicStick /></el-icon>
                使用AI快速生成
              </el-button>
            </el-empty>

            <!-- 连接线 -->
            <svg class="connections-layer" :style="canvasStyle">
              <defs>
                <marker
                  id="arrowhead"
                  markerWidth="10"
                  markerHeight="10"
                  refX="9"
                  refY="3"
                  orient="auto"
                >
                  <polygon points="0 0, 10 3, 0 6" fill="#409eff" />
                </marker>
              </defs>
              <path
                v-for="(conn, index) in connections"
                :key="index"
                :d="getConnectionPath(conn)"
                stroke="#409eff"
                stroke-width="2"
                fill="none"
                marker-end="url(#arrowhead)"
                class="connection-line"
              />
            </svg>

            <!-- 流程节点 -->
            <div
              v-for="(node, index) in flowNodes"
              :key="node.id"
              class="flow-node"
              :class="{ 
                active: selectedNodeId === node.id,
                [node.type]: true
              }"
              :style="getNodeStyle(node)"
              @click.stop="selectNode(node.id)"
              @mousedown="startDrag(node, $event)"
            >
              <div class="node-header" :style="{ background: getNodeColor(node.type) }">
                <el-icon><component :is="getNodeIcon(node.type)" /></el-icon>
                <span>{{ node.label }}</span>
              </div>
              <div class="node-body">
                <div class="node-content">
                  {{ node.config?.description || '点击配置节点' }}
                </div>
              </div>

              <!-- 连接点 -->
              <div class="node-anchor anchor-top" @mousedown.stop="startConnection(node, 'top')"></div>
              <div class="node-anchor anchor-right" @mousedown.stop="startConnection(node, 'right')"></div>
              <div class="node-anchor anchor-bottom" @mousedown.stop="startConnection(node, 'bottom')"></div>
              <div class="node-anchor anchor-left" @mousedown.stop="startConnection(node, 'left')"></div>

              <!-- 删除按钮 -->
              <div class="node-delete" @click.stop="deleteNode(index)">
                <el-icon><Close /></el-icon>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧属性面板 -->
      <div class="property-panel">
        <el-tabs v-model="propertyTab">
          <el-tab-pane label="节点属性" name="node">
            <div v-if="selectedNode" class="property-form">
              <el-form label-width="80px" size="small">
                <el-form-item label="节点ID">
                  <el-input v-model="selectedNode.id" disabled />
                </el-form-item>
                <el-form-item label="节点名称">
                  <el-input v-model="selectedNode.label" placeholder="请输入节点名称" />
                </el-form-item>

                <el-divider />

                <!-- 审批节点配置 -->
                <template v-if="selectedNode.type === 'approval'">
                  <el-form-item label="审批人">
                    <el-select v-model="selectedNode.config.approver" placeholder="选择审批人">
                      <el-option label="直属上级" value="manager" />
                      <el-option label="部门负责人" value="dept_manager" />
                      <el-option label="指定人员" value="specific" />
                    </el-select>
                  </el-form-item>
                  <el-form-item label="超时时间">
                    <el-input-number v-model="selectedNode.config.timeout" :min="1" />
                    <span class="form-tip">小时</span>
                  </el-form-item>
                  <el-form-item label="自动同意">
                    <el-switch v-model="selectedNode.config.autoApprove" />
                  </el-form-item>
                </template>

                <!-- 条件节点配置 -->
                <template v-if="selectedNode.type === 'condition'">
                  <el-form-item label="条件表达式">
                    <el-input 
                      v-model="selectedNode.config.expression" 
                      type="textarea"
                      :rows="3"
                      placeholder="如：amount > 1000"
                    />
                  </el-form-item>
                </template>

                <!-- 通知节点配置 -->
                <template v-if="selectedNode.type === 'notify'">
                  <el-form-item label="通知方式">
                    <el-checkbox-group v-model="selectedNode.config.methods">
                      <el-checkbox label="email">邮件</el-checkbox>
                      <el-checkbox label="sms">短信</el-checkbox>
                      <el-checkbox label="system">系统消息</el-checkbox>
                    </el-checkbox-group>
                  </el-form-item>
                  <el-form-item label="通知内容">
                    <el-input 
                      v-model="selectedNode.config.content" 
                      type="textarea"
                      :rows="3"
                    />
                  </el-form-item>
                </template>

                <el-divider />

                <el-form-item label="节点说明">
                  <el-input 
                    v-model="selectedNode.config.description" 
                    type="textarea"
                    :rows="3"
                    placeholder="请输入节点说明"
                  />
                </el-form-item>
              </el-form>
            </div>
            <el-empty v-else description="请选择一个节点" />
          </el-tab-pane>

          <el-tab-pane label="流程属性" name="flow">
            <div class="property-form">
              <el-form label-width="80px" size="small">
                <el-form-item label="流程名称">
                  <el-input v-model="flowData.name" placeholder="请输入流程名称" />
                </el-form-item>
                <el-form-item label="流程分类">
                  <el-select v-model="flowData.category">
                    <el-option label="审批流程" value="approval" />
                    <el-option label="业务流程" value="business" />
                    <el-option label="自动化流程" value="automation" />
                  </el-select>
                </el-form-item>
                <el-form-item label="流程描述">
                  <el-input v-model="flowData.description" type="textarea" :rows="3" />
                </el-form-item>
                <el-form-item label="启用状态">
                  <el-switch v-model="flowData.enabled" />
                </el-form-item>
              </el-form>
            </div>
          </el-tab-pane>
        </el-tabs>
      </div>
    </div>

    <!-- AI助手对话框 -->
    <el-dialog v-model="showAIDialog" title="AI流程助手" width="800px">
      <el-alert 
        title="AI可以帮你快速生成流程"
        type="info"
        :closable="false"
        style="margin-bottom: 20px"
      >
        <template #default>
          <div>示例：创建一个请假审批流程，包含申请、主管审批、HR审批</div>
        </template>
      </el-alert>

      <el-input
        v-model="aiInput"
        type="textarea"
        :rows="5"
        placeholder="描述你想创建的流程..."
        @keydown.ctrl.enter="handleAIGenerate"
      />

      <template #footer>
        <el-button @click="showAIDialog = false">取消</el-button>
        <el-button type="primary" @click="handleAIGenerate" :loading="aiGenerating">
          <el-icon><MagicStick /></el-icon>
          生成流程
        </el-button>
      </template>
    </el-dialog>

    <!-- 预览对话框 -->
    <el-dialog v-model="showPreview" title="流程预览" width="90%">
      <div class="flow-preview">
        <el-descriptions title="流程信息" :column="2" border>
          <el-descriptions-item label="流程名称">{{ flowData.name }}</el-descriptions-item>
          <el-descriptions-item label="流程分类">{{ flowData.category }}</el-descriptions-item>
          <el-descriptions-item label="节点数量">{{ flowNodes.length }}</el-descriptions-item>
          <el-descriptions-item label="连接数量">{{ connections.length }}</el-descriptions-item>
        </el-descriptions>

        <el-divider />

        <div class="preview-nodes">
          <h4>流程步骤：</h4>
          <el-steps :active="flowNodes.length - 1" align-center>
            <el-step 
              v-for="node in flowNodes" 
              :key="node.id"
              :title="node.label"
              :description="node.config?.description"
            />
          </el-steps>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
  ArrowLeft, View, MagicStick, Select, Promotion, Delete,
  RefreshLeft, RefreshRight, ZoomIn, ZoomOut, FullScreen, Close
} from '@element-plus/icons-vue'

// 状态
const propertyTab = ref('node')
const isSaved = ref(true)
const selectedNodeId = ref(null)
const showAIDialog = ref(false)
const showPreview = ref(false)
const aiInput = ref('')
const aiGenerating = ref(false)
const zoomLevel = ref(1)
const canvasRef = ref(null)

// 拖拽和连线状态
const isDragging = ref(false)
const dragNode = ref(null)
const dragStartPos = ref({ x: 0, y: 0 })
const isConnecting = ref(false)
const connectStart = ref(null)

// 流程数据
const flowData = reactive({
  name: '新建流程',
  category: 'approval',
  description: '',
  enabled: true
})

// 流程节点
const flowNodes = ref([])

// 节点连接
const connections = ref([])

// 历史记录
const history = ref([])
const historyIndex = ref(-1)

const canUndo = computed(() => historyIndex.value > 0)
const canRedo = computed(() => historyIndex.value < history.value.length - 1)

// 选中的节点
const selectedNode = computed(() => {
  return flowNodes.value.find(n => n.id === selectedNodeId.value)
})

// 流程有效性
const isValidFlow = computed(() => {
  return flowNodes.value.length >= 2 && connections.value.length >= 1
})

// 画布样式
const canvasStyle = computed(() => ({
  transform: `scale(${zoomLevel.value})`,
  transformOrigin: 'top left'
}))

// 节点类型
const nodeTypes = [
  { type: 'start', label: '开始', icon: 'CaretRight', color: '#67c23a' },
  { type: 'approval', label: '审批', icon: 'CircleCheck', color: '#409eff' },
  { type: 'condition', label: '条件', icon: 'Operation', color: '#e6a23c' },
  { type: 'notify', label: '通知', icon: 'Bell', color: '#909399' },
  { type: 'task', label: '任务', icon: 'DocumentChecked', color: '#409eff' },
  { type: 'end', label: '结束', icon: 'CircleClose', color: '#f56c6c' }
]

// 拖拽开始
let dragComponentType = null

const handleDragStart = (node) => {
  dragComponentType = node
}

const handleDrop = (e) => {
  if (dragComponentType) {
    const rect = canvasRef.value.getBoundingClientRect()
    const x = (e.clientX - rect.left) / zoomLevel.value
    const y = (e.clientY - rect.top) / zoomLevel.value

    const newNode = {
      id: `node_${Date.now()}`,
      type: dragComponentType.type,
      label: dragComponentType.label,
      x: x - 75,
      y: y - 40,
      config: {
        description: '',
        approver: '',
        timeout: 24,
        autoApprove: false,
        expression: '',
        methods: [],
        content: ''
      }
    }

    flowNodes.value.push(newNode)
    isSaved.value = false
    saveHistory()
    dragComponentType = null
  }
}

// 节点拖动
const startDrag = (node, e) => {
  if (e.button !== 0) return
  
  isDragging.value = true
  dragNode.value = node
  dragStartPos.value = {
    x: e.clientX - node.x * zoomLevel.value,
    y: e.clientY - node.y * zoomLevel.value
  }

  const handleMouseMove = (e) => {
    if (isDragging.value && dragNode.value) {
      dragNode.value.x = (e.clientX - dragStartPos.value.x) / zoomLevel.value
      dragNode.value.y = (e.clientY - dragStartPos.value.y) / zoomLevel.value
    }
  }

  const handleMouseUp = () => {
    isDragging.value = false
    dragNode.value = null
    document.removeEventListener('mousemove', handleMouseMove)
    document.removeEventListener('mouseup', handleMouseUp)
    if (!isSaved.value) {
      saveHistory()
    }
  }

  document.addEventListener('mousemove', handleMouseMove)
  document.addEventListener('mouseup', handleMouseUp)
}

// 开始连接
const startConnection = (node, anchor) => {
  isConnecting.value = true
  connectStart.value = { nodeId: node.id, anchor }
}

// 获取节点样式
const getNodeStyle = (node) => {
  return {
    left: node.x + 'px',
    top: node.y + 'px'
  }
}

// 获取节点颜色
const getNodeColor = (type) => {
  const node = nodeTypes.find(n => n.type === type)
  return node?.color || '#409eff'
}

// 获取节点图标
const getNodeIcon = (type) => {
  const node = nodeTypes.find(n => n.type === type)
  return node?.icon || 'CircleCheck'
}

// 获取连接路径
const getConnectionPath = (conn) => {
  const fromNode = flowNodes.value.find(n => n.id === conn.from)
  const toNode = flowNodes.value.find(n => n.id === conn.to)
  
  if (!fromNode || !toNode) return ''

  const fromX = fromNode.x + 75
  const fromY = fromNode.y + 80
  const toX = toNode.x + 75
  const toY = toNode.y

  // 简单的直线连接
  return `M ${fromX} ${fromY} L ${toX} ${toY}`
}

// 选择节点
const selectNode = (id) => {
  selectedNodeId.value = id
}

// 取消选择
const deselectAll = () => {
  selectedNodeId.value = null
}

// 删除节点
const deleteNode = (index) => {
  const nodeId = flowNodes.value[index].id
  
  // 删除相关连接
  connections.value = connections.value.filter(
    conn => conn.from !== nodeId && conn.to !== nodeId
  )
  
  flowNodes.value.splice(index, 1)
  selectedNodeId.value = null
  isSaved.value = false
  saveHistory()
}

// 画布操作
const handleZoomIn = () => {
  zoomLevel.value = Math.min(zoomLevel.value + 0.1, 2)
}

const handleZoomOut = () => {
  zoomLevel.value = Math.max(zoomLevel.value - 0.1, 0.5)
}

const handleFitView = () => {
  zoomLevel.value = 1
}

const handleClear = () => {
  ElMessageBox.confirm('确定要清空所有节点吗？', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    flowNodes.value = []
    connections.value = []
    selectedNodeId.value = null
    isSaved.value = false
    saveHistory()
    ElMessage.success('已清空')
  })
}

const saveHistory = () => {
  history.value = history.value.slice(0, historyIndex.value + 1)
  history.value.push({
    nodes: JSON.parse(JSON.stringify(flowNodes.value)),
    connections: JSON.parse(JSON.stringify(connections.value))
  })
  historyIndex.value = history.value.length - 1
}

const handleUndo = () => {
  if (canUndo.value) {
    historyIndex.value--
    const state = history.value[historyIndex.value]
    flowNodes.value = JSON.parse(JSON.stringify(state.nodes))
    connections.value = JSON.parse(JSON.stringify(state.connections))
  }
}

const handleRedo = () => {
  if (canRedo.value) {
    historyIndex.value++
    const state = history.value[historyIndex.value]
    flowNodes.value = JSON.parse(JSON.stringify(state.nodes))
    connections.value = JSON.parse(JSON.stringify(state.connections))
  }
}

const handlePreview = () => {
  showPreview.value = true
}

const handleSave = () => {
  console.log('保存流程:', { flowData, nodes: flowNodes.value, connections: connections.value })
  isSaved.value = true
  ElMessage.success('保存成功')
}

const handlePublish = () => {
  if (!isValidFlow.value) {
    ElMessage.warning('流程不完整，至少需要2个节点和1个连接')
    return
  }

  ElMessageBox.confirm('确定要发布此流程吗？', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'info'
  }).then(() => {
    handleSave()
    ElMessage.success('发布成功')
  })
}

// AI生成
const handleAIGenerate = () => {
  if (!aiInput.value.trim()) {
    ElMessage.warning('请输入需求描述')
    return
  }

  aiGenerating.value = true

  setTimeout(() => {
    // 生成一个标准审批流程
    flowData.name = 'AI生成的审批流程'
    flowData.category = 'approval'
    
    flowNodes.value = [
      {
        id: 'node_start',
        type: 'start',
        label: '开始',
        x: 100,
        y: 100,
        config: { description: '发起申请' }
      },
      {
        id: 'node_approval1',
        type: 'approval',
        label: '主管审批',
        x: 350,
        y: 100,
        config: { 
          description: '主管审批',
          approver: 'manager',
          timeout: 24,
          autoApprove: false
        }
      },
      {
        id: 'node_approval2',
        type: 'approval',
        label: 'HR审批',
        x: 600,
        y: 100,
        config: { 
          description: 'HR审批',
          approver: 'dept_manager',
          timeout: 48,
          autoApprove: false
        }
      },
      {
        id: 'node_end',
        type: 'end',
        label: '结束',
        x: 850,
        y: 100,
        config: { description: '流程结束' }
      }
    ]

    connections.value = [
      { from: 'node_start', to: 'node_approval1' },
      { from: 'node_approval1', to: 'node_approval2' },
      { from: 'node_approval2', to: 'node_end' }
    ]

    ElMessage.success('流程生成成功')
    aiGenerating.value = false
    showAIDialog.value = false
    isSaved.value = false
    saveHistory()
  }, 2000)
}

// 初始化
saveHistory()
</script>

<style scoped>
.flow-designer {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: #f5f5f5;
}

.designer-header {
  height: 60px;
  background: white;
  border-bottom: 1px solid #e6e6e6;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 20px;
}

.header-left {
  display: flex;
  align-items: center;
  gap: 15px;
}

.back-icon {
  font-size: 20px;
  cursor: pointer;
}

.title {
  font-size: 18px;
  font-weight: bold;
}

.header-actions {
  display: flex;
  gap: 10px;
}

.designer-body {
  flex: 1;
  display: flex;
  overflow: hidden;
}

.node-panel {
  width: 240px;
  background: white;
  border-right: 1px solid #e6e6e6;
  overflow-y: auto;
  padding: 15px;
}

.panel-title {
  font-weight: bold;
  margin-bottom: 15px;
  color: #303133;
}

.node-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.node-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  background: #f9f9f9;
  border: 1px solid #e6e6e6;
  border-radius: 6px;
  cursor: move;
  transition: all 0.3s;
}

.node-item:hover {
  transform: translateX(5px);
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.node-icon {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 18px;
}

.node-label {
  font-size: 14px;
  color: #303133;
}

.flow-info {
  padding: 10px;
  background: #f9f9f9;
  border-radius: 6px;
}

.info-item {
  display: flex;
  justify-content: space-between;
  margin-bottom: 8px;
  font-size: 13px;
}

.info-item .label {
  color: #909399;
}

.info-item .value {
  font-weight: bold;
  color: #303133;
}

.canvas-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.canvas-toolbar {
  height: 50px;
  background: white;
  border-bottom: 1px solid #e6e6e6;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 20px;
}

.zoom-level {
  font-size: 14px;
  color: #606266;
  font-weight: bold;
}

.canvas-container {
  flex: 1;
  overflow: auto;
  background: 
    linear-gradient(90deg, #f0f0f0 1px, transparent 1px),
    linear-gradient(#f0f0f0 1px, transparent 1px);
  background-size: 20px 20px;
  position: relative;
}

.canvas-content {
  position: relative;
  min-width: 2000px;
  min-height: 1500px;
}

.connections-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.connection-line {
  cursor: pointer;
  pointer-events: all;
}

.connection-line:hover {
  stroke: #f56c6c;
  stroke-width: 3;
}

.flow-node {
  position: absolute;
  width: 150px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  cursor: move;
  transition: all 0.3s;
}

.flow-node:hover {
  box-shadow: 0 4px 16px rgba(0,0,0,0.15);
  transform: translateY(-2px);
}

.flow-node.active {
  box-shadow: 0 0 0 2px #409eff;
}

.node-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px;
  color: white;
  border-radius: 8px 8px 0 0;
  font-weight: bold;
  font-size: 14px;
}

.node-body {
  padding: 12px;
}

.node-content {
  font-size: 12px;
  color: #606266;
  min-height: 40px;
}

.node-anchor {
  position: absolute;
  width: 10px;
  height: 10px;
  background: #409eff;
  border: 2px solid white;
  border-radius: 50%;
  cursor: crosshair;
  opacity: 0;
  transition: opacity 0.3s;
}

.flow-node:hover .node-anchor {
  opacity: 1;
}

.anchor-top {
  top: -5px;
  left: 50%;
  transform: translateX(-50%);
}

.anchor-right {
  right: -5px;
  top: 50%;
  transform: translateY(-50%);
}

.anchor-bottom {
  bottom: -5px;
  left: 50%;
  transform: translateX(-50%);
}

.anchor-left {
  left: -5px;
  top: 50%;
  transform: translateY(-50%);
}

.node-delete {
  position: absolute;
  top: -10px;
  right: -10px;
  width: 24px;
  height: 24px;
  background: #f56c6c;
  color: white;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.3s;
}

.flow-node:hover .node-delete {
  opacity: 1;
}

.node-delete:hover {
  background: #f78989;
}

.property-panel {
  width: 300px;
  background: white;
  border-left: 1px solid #e6e6e6;
  overflow-y: auto;
}

.property-form {
  padding: 15px;
}

.form-tip {
  margin-left: 10px;
  color: #909399;
  font-size: 12px;
}

.flow-preview {
  padding: 20px;
}

.preview-nodes {
  margin-top: 20px;
}

.preview-nodes h4 {
  margin-bottom: 20px;
  color: #303133;
}
</style>
